//! Declaration parser for NRC language

use super::Parser;
use crate::ast::decl::*;
use crate::error::Result;
use crate::lexer::token::Token;

// Sub-modules
mod enum_decl;
mod function;
mod helpers;
mod impl_decl;
mod import;
mod struct_decl;
mod trait_decl;
mod trait_impl;
mod type_decl;
mod variable;

// Re-exports
pub use enum_decl::{parse_enum_declaration, parse_enum_declaration_from_current};
pub use function::parse_function_declaration;
pub use helpers::{parse_attributes, parse_block};
pub use impl_decl::parse_impl_declaration;
pub use import::parse_import_declaration;
pub use struct_decl::{
    parse_go_style_struct_declaration, parse_go_style_struct_declaration_from_current,
    parse_struct_declaration,
};
pub use trait_decl::{parse_trait_declaration, parse_trait_declaration_from_current};
pub use trait_impl::parse_trait_impl_declaration;
pub use type_decl::parse_type_declaration;
pub use variable::{parse_constant_declaration, parse_variable_declaration};

/// Parse a declaration
pub fn parse_declaration(parser: &mut Parser) -> Result<Option<Declaration>> {
    if parser.is_at_end() {
        return Ok(None);
    }

    match parser.peek() {
        Some(token) => match &token.token {
            Token::Fn => {
                let decl = parse_function_declaration(parser)?;
                Ok(Some(Declaration::Function(decl)))
            }
            Token::Var => {
                let decl = parse_variable_declaration(parser)?;
                Ok(Some(Declaration::Variable(decl)))
            }
            Token::Const => {
                let decl = parse_constant_declaration(parser)?;
                Ok(Some(Declaration::Constant(decl)))
            }
            Token::Type => {
                // Check if this is a Go-style struct declaration, enum declaration, or trait declaration
                let current_pos = parser.current.clone();
                parser.advance()?; // consume 'type'

                if let Some(Token::Identifier(name)) = parser.peek().map(|t| &t.token) {
                    let type_name = name.clone();
                    parser.advance()?; // consume identifier

                    let next_token = parser.peek_token_after_generics()?;

                    if matches!(next_token, Some(Token::Struct)) {
                        // This is a Go-style struct declaration
                        parser.current = current_pos; // restore position
                        let struct_decl = parse_go_style_struct_declaration(parser)?;
                        Ok(Some(Declaration::Struct(struct_decl)))
                    } else if matches!(next_token, Some(Token::Enum)) {
                        // This is an enum declaration
                        parser.current = current_pos; // restore position
                        let enum_decl = parse_enum_declaration(parser)?;
                        Ok(Some(Declaration::Enum(enum_decl)))
                    } else if matches!(next_token, Some(Token::Trait)) {
                        // This is a trait declaration
                        parser.current = current_pos; // restore position
                        parser.advance()?; // consume 'type'
                        parser.advance()?; // consume identifier
                                           // Note: parse_trait_declaration_from_current will handle generic parameters
                        let trait_decl = parse_trait_declaration_from_current(parser, type_name)?;
                        Ok(Some(Declaration::Trait(trait_decl)))
                    } else {
                        // This is a regular type declaration
                        parser.current = current_pos; // restore position
                        let decl = parse_type_declaration(parser)?;
                        Ok(Some(Declaration::Type(decl)))
                    }
                } else {
                    // This is a regular type declaration
                    parser.current = current_pos; // restore position
                    let decl = parse_type_declaration(parser)?;
                    Ok(Some(Declaration::Type(decl)))
                }
            }
            Token::Import => {
                let decl = parse_import_declaration(parser)?;
                Ok(Some(Declaration::Import(decl)))
            }
            Token::Impl => {
                // Check if this is impl Trait for Type syntax
                // We need to peek ahead to see if there's a 'for' keyword
                let peek_pos = parser.current.clone();
                parser.advance()?; // consume 'impl'

                if let Some(Token::Identifier(_)) = parser.peek().map(|t| &t.token) {
                    parser.advance()?; // consume identifier
                    if parser.check(&Token::For) {
                        // This is a trait implementation
                        // Restore position and clear buffer
                        parser.current = peek_pos;
                        parser.buffer.clear();
                        let trait_impl = parse_trait_impl_declaration(parser)?;
                        Ok(Some(Declaration::TraitImpl(trait_impl)))
                    } else {
                        // This is a regular impl Type { ... }
                        // Restore position and clear buffer
                        parser.current = peek_pos;
                        parser.buffer.clear();
                        let decl = parse_impl_declaration(parser)?;
                        Ok(Some(Declaration::Impl(decl)))
                    }
                } else {
                    // This is a regular impl Type { ... }
                    // Restore position and clear buffer
                    parser.current = peek_pos;
                    parser.buffer.clear();
                    let decl = parse_impl_declaration(parser)?;
                    Ok(Some(Declaration::Impl(decl)))
                }
            }
            _ => Ok(None),
        },
        None => Ok(None),
    }
}
